package com.streamax.s17.mqs.business.common;

import com.streamax.s17.boot.starter.interceptor.WebInterceptor;
import com.streamax.s17.cloud.common.BusinessException;
import com.streamax.s17.cloud.common.model.ResponseCode;
import com.streamax.s17.cloud.common.model.ResponseResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.javassist.NotFoundException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @program: dtms
 * @description: 全局异常处理
 * @author: YangYang ST02002
 * @create: 2018-11-07
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    private static final ObjectError UNKNOWN_PARAM_ERROR = new ObjectError("unknown", "未知参数错误！");

    /**
     * 系统内部异常
     *
     * @param e        异常对象
     * @param request  请求对象
     * @param response 返回信息
     * @return 返回异常信息
     */
    @ExceptionHandler(Exception.class)
    public ResponseResult handleException(Exception e, HttpServletRequest request, HttpServletResponse response) {
        Map trackInfoMap = (HashMap) request.getAttribute(WebInterceptor.TRACK_PARAM);
        String trackId = null == trackInfoMap ? "undefined" : trackInfoMap.getOrDefault(WebInterceptor.PARAM_KEY_TRACK_ID, "").toString();

        // 请求不完整
        if (e instanceof MissingServletRequestParameterException) {
            MissingServletRequestParameterException exception = ((MissingServletRequestParameterException) e);
            String message = MessageFormat.format("track_{0} MissingServletRequestParameterException={1}",
                    trackId,
                    exception.getLocalizedMessage());
            log.info(message);
            return ResponseResult.of(ResponseCode.REQUEST_RESOLVE_FAIL, ": 缺失" + exception.getParameterName());
        }

        // mybatis 的 xml 参数错误
        if (e instanceof NotFoundException) {
            String message = MessageFormat.format("track_{0} NotFoundException=", trackId);
            log.error(message, e);
            return ResponseResult.of(ResponseCode.SYSTEM_EXCEPTION);
        }

        // 统一参数校验
        if (e instanceof BindException || e instanceof MethodArgumentNotValidException) {
            List<ObjectError> errors = e instanceof BindException ? ((BindException) e).getAllErrors()
                    : ((MethodArgumentNotValidException) e).getBindingResult().getAllErrors();
            ObjectError error = null == errors || errors.isEmpty() ? UNKNOWN_PARAM_ERROR : errors.get(0);
            String message = MessageFormat.format("track_{0} BindException | MethodArgumentNotValidException: objectName {1}, {2}, {3}",
                    trackId,
                    error.getObjectName(),
                    error.getDefaultMessage(),
                    error.getCode());
            log.info(message);
            String errMsg = error.getDefaultMessage();
            return ResponseResult.of(ResponseCode.ERROR_PARAMETER, ": " + errMsg);
        }
        if (e instanceof HttpMessageNotReadableException) {
            log.info("track_{} HttpMessageNotReadableException: message={}", trackId, e.getLocalizedMessage());
            return ResponseResult.of(ResponseCode.ERROR_PARAMETER);
        }

        // 请求方式不存在
        if (e instanceof HttpRequestMethodNotSupportedException) {
            String method = ((HttpRequestMethodNotSupportedException) e).getMethod();
            log.info("track_{} unsupported method {}_{}", trackId, method, request.getRequestURI());
            return ResponseResult.of(ResponseCode.NOT_FOUND, ": " + "不支持的请求方式 " + method.toUpperCase());
        }

        // 业务异常
        if (e instanceof MqsBusinessException) {
            MqsBusinessException exception = (MqsBusinessException) e;
            String message = MessageFormat.format("track_{0} MqsBusinessException=", trackId);
            log.info(message, e);
            return ResponseResult.of(ResponseCode.RESOURCE_INJECT, exception.getMessage());
        }
        if (e instanceof BusinessException) {
            BusinessException exception = (BusinessException) e;
            String message = MessageFormat.format("track_{0} BusinessException=", trackId);
            log.info(message, e);
            return ResponseResult.of(ResponseCode.RESOURCE_INJECT, exception);
        }

        String message = MessageFormat.format("track_{0} GlobalExceptionHandler=", trackId);
        log.error(message, e);
        return ResponseResult.of(ResponseCode.SYSTEM_EXCEPTION);
    }

}
